home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / gnustuff / tos / g__~1 / gplibs17.zoo / sbufvsca.cc < prev    next >
Encoding:
C/C++ Source or Header  |  1993-03-02  |  17.0 KB  |  751 lines

  1. /*
  2.  * Copyright (c) 1990 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that the above copyright notice and this paragraph are
  7.  * duplicated in all such forms and that any documentation,
  8.  * advertising materials, and other materials related to such
  9.  * distribution and use acknowledge that the software was developed
  10.  * by the University of California, Berkeley.  The name of the
  11.  * University may not be used to endorse or promote products derived
  12.  * from this software without specific prior written permission.
  13.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
  14.  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  15.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  16.  */
  17.  
  18. // Extensively hacked for GNU iostream by Per Bothner 1991, 1992.
  19. // Changes copyright Per Bothner 1992.
  20.  
  21. #if defined(LIBC_SCCS) && !defined(lint)
  22. static char sccsid[] = "%W% (Berkeley) %G%";
  23. #endif /* LIBC_SCCS and not lint */
  24.  
  25. #include <ioprivat.h>
  26. #include <ctype.h>
  27. #ifndef NO_STDARG
  28. #include <stdarg.h>
  29. #else
  30. #include <varargs.h>
  31. #endif
  32.  
  33. #ifndef    NO_FLOATING_POINT
  34. #define FLOATING_POINT
  35. #endif
  36.  
  37. #ifdef FLOATING_POINT
  38. #include <floatio.h>
  39. #define    BUF    (MAXEXP+MAXFRACT+3)    /* 3 = sign + decimal point + NUL */
  40. #else
  41. #define    BUF    40
  42. #endif
  43.  
  44. /*
  45.  * Flags used during conversion.
  46.  */
  47. #define    LONG        0x01    /* l: long or double */
  48. #define    LONGDBL        0x02    /* L: long double; unimplemented */
  49. #define    SHORT        0x04    /* h: short */
  50. #define    SUPPRESS    0x08    /* suppress assignment */
  51. #define    POINTER        0x10    /* weird %p pointer (`fake hex') */
  52. #define    NOSKIP        0x20    /* do not skip blanks */
  53.  
  54. /*
  55.  * The following are used in numeric conversions only:
  56.  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
  57.  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
  58.  */
  59. #define    SIGNOK        0x40    /* +/- is (still) legal */
  60. #define    NDIGITS        0x80    /* no digits detected */
  61.  
  62. #define    DPTOK        0x100    /* (float) decimal point is still legal */
  63. #define    EXPOK        0x200    /* (float) exponent (e+3, etc) still legal */
  64.  
  65. #define    PFXOK        0x100    /* 0x prefix is (still) legal */
  66. #define    NZDIGITS    0x200    /* no zero digits detected */
  67.  
  68. /*
  69.  * Conversion types.
  70.  */
  71. #define    CT_CHAR        0    /* %c conversion */
  72. #define    CT_CCL        1    /* %[...] conversion */
  73. #define    CT_STRING    2    /* %s conversion */
  74. #define    CT_INT        3    /* integer, i.e., strtol or strtoul */
  75. #define    CT_FLOAT    4    /* floating, i.e., strtod */
  76.  
  77. #define u_char unsigned char
  78. #define u_long unsigned long
  79.  
  80. extern "C" u_long strtoul(const char*, char**, int);
  81. static const u_char *__sccl(register char *tab, register const u_char *fmt);
  82.  
  83. // If state is non-NULL, set failbit and/or eofbit as appropriate.
  84.  
  85. int streambuf::vscan(char const *fmt0,
  86.              _G_va_list ap,
  87.              ios *stream /* = NULL */)
  88. {
  89.     register const u_char *fmt = (const u_char *)fmt0;
  90.     register int c;        /* character from format, or conversion */
  91.     register size_t width;    /* field width, or 0 */
  92.     register char *p;    /* points into all kinds of strings */
  93.     register int n;        /* handy integer */
  94.     register int flags;    /* flags as defined above */
  95.     register char *p0;    /* saves original value of p when necessary */
  96.     int nassigned;        /* number of fields assigned */
  97.     int nread;        /* number of characters consumed from fp */
  98.     // Assignments to base and ccfn are just to suppress warnings from gcc.
  99.     int base = 0;        /* base argument to strtol/strtoul */
  100.     u_long (*ccfn)(const char*, char**, int) = 0;
  101.     // conversion function (strtol/strtoul)
  102.     char ccltab[256];    /* character class table for %[...] */
  103.     char buf[BUF];        /* buffer for numeric conversions */
  104.     int seen_eof = 0;
  105.  
  106.     /* `basefix' is used to avoid `if' tests in the integer scanner */
  107.     static short basefix[17] =
  108.         { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
  109.  
  110.     nassigned = 0;
  111.     nread = 0;
  112.     for (;;) {
  113.         c = *fmt++;
  114.         if (c == 0)
  115.             goto done;
  116.         if (isspace(c)) {
  117.             for (;;) {
  118.                     c = sbumpc();
  119.                 if (c == EOF)
  120.                     goto eof_failure;
  121.                 if (!isspace(c)) {
  122.                     sputbackc(c);
  123.                     break;
  124.                 }
  125.                 nread++;
  126.             }
  127.             continue;
  128.         }
  129.         if (c != '%')
  130.             goto literal;
  131.         width = 0;
  132.         flags = 0;
  133.         /*
  134.          * switch on the format.  continue if done;
  135.          * break once format type is derived.
  136.          */
  137. again:        c = *fmt++;
  138.         switch (c) {
  139.         case '%':
  140. literal:
  141.                 n = sbumpc();
  142.             if (n == EOF)
  143.                 goto eof_failure;
  144.             if (n != c) {
  145.                 sputbackc(n);
  146.                 goto match_failure;
  147.             }
  148.             nread++;
  149.             continue;
  150.  
  151.         case '*':
  152.             flags |= SUPPRESS;
  153.             goto again;
  154.         case 'l':
  155.             flags |= LONG;
  156.             goto again;
  157.         case 'L':
  158.             flags |= LONGDBL;
  159.             goto again;
  160.         case 'h':
  161.             flags |= SHORT;
  162.             goto again;
  163.  
  164.         case '0': case '1': case '2': case '3': case '4':
  165.         case '5': case '6': case '7': case '8': case '9':
  166.             width = width * 10 + c - '0';
  167.             goto again;
  168.  
  169.         /*
  170.          * Conversions.
  171.          * Those marked `compat' are for 4.[123]BSD compatibility.
  172.          *
  173.          * (According to ANSI, E and X formats are supposed
  174.          * to the same as e and x.  Sorry about that.)
  175.          */
  176.         case 'D':    /* compat */
  177.             flags |= LONG;
  178.             /* FALLTHROUGH */
  179.         case 'd':
  180.             c = CT_INT;
  181.             ccfn = (u_long (*)(const char, char**, int))strtol;
  182.             base = 10;
  183.             break;
  184.  
  185.         case 'i':
  186.             c = CT_INT;
  187.             ccfn = (u_long (*)(const char, char**, int))strtol;
  188.             base = 0;
  189.             break;
  190.  
  191.         case 'O':    /* compat */
  192.             flags |= LONG;
  193.             /* FALLTHROUGH */
  194.         case 'o':
  195.             c = CT_INT;
  196.             ccfn = strtoul;
  197.             base = 8;
  198.             break;
  199.  
  200.         case 'u':
  201.             c = CT_INT;
  202.             ccfn = strtoul;
  203.             base = 10;
  204.             break;
  205.  
  206.         case 'X':    /* compat   XXX */
  207.             flags |= LONG;
  208.             /* FALLTHROUGH */
  209.         case 'x':
  210.             flags |= PFXOK;    /* enable 0x prefixing */
  211.             c = CT_INT;
  212.             ccfn = strtoul;
  213.             base = 16;
  214.             break;
  215.  
  216. #ifdef FLOATING_POINT
  217.         case 'E':    /* compat   XXX */
  218.         case 'F':    /* compat */
  219.             flags |= LONG;
  220.             /* FALLTHROUGH */
  221.         case 'e': case 'f': case 'g':
  222.             c = CT_FLOAT;
  223.             break;
  224. #endif
  225.  
  226.         case 's':
  227.             c = CT_STRING;
  228.             break;
  229.  
  230.         case '[':
  231.             fmt = __sccl(ccltab, fmt);
  232.             flags |= NOSKIP;
  233.             c = CT_CCL;
  234.             break;
  235.  
  236.         case 'c':
  237.             flags |= NOSKIP;
  238.             c = CT_CHAR;
  239.             break;
  240.  
  241.         case 'p':    /* pointer format is like hex */
  242.             flags |= POINTER | PFXOK;
  243.             c = CT_INT;
  244.             ccfn = strtoul;
  245.             base = 16;
  246.             break;
  247.  
  248.         case 'n':
  249.             if (flags & SUPPRESS)    /* ??? */
  250.                 continue;
  251.             if (flags & SHORT)
  252.                 *va_arg(ap, short *) = nread;
  253.             else if (flags & LONG)
  254.                 *va_arg(ap, long *) = nread;
  255.             else
  256.                 *va_arg(ap, int *) = nread;
  257.             continue;
  258.  
  259.         /*
  260.          * Disgusting backwards compatibility hacks.    XXX
  261.          */
  262.         case '\0':    /* compat */
  263.                 nassigned = EOF;
  264.             goto done;
  265.  
  266.         default:    /* compat */
  267.             if (isupper(c))
  268.                 flags |= LONG;
  269.             c = CT_INT;
  270.             ccfn = (u_long (*)(const char, char**, int))strtol;
  271.             base = 10;
  272.             break;
  273.         }
  274.  
  275.         /*
  276.          * We have a conversion that requires input.
  277.          */
  278.         if (sgetc() == EOF)
  279.             goto eof_failure;
  280.  
  281.         /*
  282.          * Consume leading white space, except for formats
  283.          * that suppress this.
  284.          */
  285.         if ((flags & NOSKIP) == 0) {
  286.             n = *_gptr;
  287.             while (isspace(n)) {
  288.             _gptr++;
  289.             nread++;
  290.             n = sgetc();
  291.             if (n == EOF)
  292.                 goto eof_failure;
  293.             }
  294.             // Note that there is at least one character in
  295.             // the buffer, so conversions that do not set NOSKIP
  296.             // can no longer result in an input failure.
  297.         }
  298.  
  299.         /*
  300.          * Do the conversion.
  301.          */
  302.         switch (c) {
  303.  
  304.         case CT_CHAR:
  305.             /* scan arbitrary characters (sets NOSKIP) */
  306.             if (width == 0) // FIXME!
  307.                 width = 1;
  308.             if (flags & SUPPRESS) {
  309.                 size_t sum = 0;
  310.                 for (;;) {
  311.                 if ((n = _egptr - _gptr) < (int)width) {
  312.                     sum += n;
  313.                     width -= n;
  314.                     _gptr += n;
  315.                     if (underflow() == EOF)
  316.                     if (sum == 0)
  317.                         goto eof_failure;
  318.                     else {
  319.                         seen_eof++;
  320.                         break;
  321.                     }
  322.                 } else {
  323.                     sum += width;
  324.                     _gptr += width;
  325.                     break;
  326.                 }
  327.                 }
  328.                 nread += sum;
  329.             } else {
  330.                 size_t r = sgetn((char*)va_arg(ap, char*),
  331.                          width);
  332.                 if (r != width)
  333.                 goto eof_failure;
  334.                 nread += r;
  335.                 nassigned++;
  336.             }
  337.             break;
  338.  
  339.         case CT_CCL:
  340.             /* scan a (nonempty) character class (sets NOSKIP) */
  341.             if (width == 0)
  342.                 width = ~0;    /* `infinity' */
  343.             /* take only those things in the class */
  344.             if (flags & SUPPRESS) {
  345.                 n = 0;
  346.                 while (ccltab[*_gptr]) {
  347.                     n++, _gptr++;
  348.                     if (--width == 0)
  349.                     break;
  350.                     if (sgetc() == EOF) {
  351.                     if (n == 0)
  352.                         goto eof_failure;
  353.                     seen_eof++;
  354.                     break;
  355.                     }
  356.                 }
  357.                 if (n == 0)
  358.                     goto match_failure;
  359.             } else {
  360.                 p0 = p = va_arg(ap, char *);
  361.                 while (ccltab[*_gptr]) {
  362.                 *p++ = *_gptr++;
  363.                 if (--width == 0)
  364.                     break;
  365.                 if (sgetc() == EOF) {
  366.                     if (p == p0)
  367.                     goto eof_failure;
  368.                     seen_eof++;
  369.                     break;
  370.                 }
  371.                 }
  372.                 n = p - p0;
  373.                 if (n == 0)
  374.                 goto match_failure;
  375.                 *p = 0;
  376.                 nassigned++;
  377.             }
  378.             nread += n;
  379.             break;
  380.  
  381.         case CT_STRING:
  382.             /* like CCL, but zero-length string OK, & no NOSKIP */
  383.             if (width == 0)
  384.                 width = ~0;
  385.             if (flags & SUPPRESS) {
  386.                 n = 0;
  387.                 while (!isspace(*_gptr)) {
  388.                     n++, _gptr++;
  389.                     if (--width == 0)
  390.                         break;
  391.                     if (sgetc() == EOF) {
  392.                         seen_eof++;
  393.                         break;
  394.                     }
  395.                 }
  396.                 nread += n;
  397.             } else {
  398.                 p0 = p = va_arg(ap, char *);
  399.                 while (!isspace(*_gptr)) {
  400.                     *p++ = *_gptr++;
  401.                     if (--width == 0)
  402.                         break;
  403.                     if (sgetc() == EOF) {
  404.                         seen_eof++;
  405.                         break;
  406.                     }
  407.                 }
  408.                 *p = 0;
  409.                 nread += p - p0;
  410.                 nassigned++;
  411.             }
  412.             continue;
  413.  
  414.         case CT_INT:
  415.             /* scan an integer as if by strtol/strtoul */
  416.             if (width == 0 || width > sizeof(buf) - 1)
  417.                 width = sizeof(buf) - 1;
  418.             flags |= SIGNOK | NDIGITS | NZDIGITS;
  419.             for (p = buf; width; width--) {
  420.                 c = *_gptr;
  421.                 /*
  422.                  * Switch on the character; `goto ok'
  423.                  * if we accept it as a part of number.
  424.                  */
  425.                 switch (c) {
  426.  
  427.                 /*
  428.                  * The digit 0 is always legal, but is
  429.                  * special.  For %i conversions, if no
  430.                  * digits (zero or nonzero) have been
  431.                  * scanned (only signs), we will have
  432.                  * base==0.  In that case, we should set
  433.                  * it to 8 and enable 0x prefixing.
  434.                  * Also, if we have not scanned zero digits
  435.                  * before this, do not turn off prefixing
  436.                  * (someone else will turn it off if we
  437.                  * have scanned any nonzero digits).
  438.                  */
  439.                 case '0':
  440.                     if (base == 0) {
  441.                         base = 8;
  442.                         flags |= PFXOK;
  443.                     }
  444.                     if (flags & NZDIGITS)
  445.                         flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
  446.                     else
  447.                         flags &= ~(SIGNOK|PFXOK|NDIGITS);
  448.                     goto ok;
  449.  
  450.                 /* 1 through 7 always legal */
  451.                 case '1': case '2': case '3':
  452.                 case '4': case '5': case '6': case '7':
  453.                     base = basefix[base];
  454.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  455.                     goto ok;
  456.  
  457.                 /* digits 8 and 9 ok iff decimal or hex */
  458.                 case '8': case '9':
  459.                     base = basefix[base];
  460.                     if (base <= 8)
  461.                         break;    /* not legal here */
  462.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  463.                     goto ok;
  464.  
  465.                 /* letters ok iff hex */
  466.                 case 'A': case 'B': case 'C':
  467.                 case 'D': case 'E': case 'F':
  468.                 case 'a': case 'b': case 'c':
  469.                 case 'd': case 'e': case 'f':
  470.                     /* no need to fix base here */
  471.                     if (base <= 10)
  472.                         break;    /* not legal here */
  473.                     flags &= ~(SIGNOK | PFXOK | NDIGITS);
  474.                     goto ok;
  475.  
  476.                 /* sign ok only as first character */
  477.                 case '+': case '-':
  478.                     if (flags & SIGNOK) {
  479.                         flags &= ~SIGNOK;
  480.                         goto ok;
  481.                     }
  482.                     break;
  483.  
  484.                 /* x ok iff flag still set & 2nd char */
  485.                 case 'x': case 'X':
  486.                     if (flags & PFXOK && p == buf + 1) {
  487.                         base = 16;    /* if %i */
  488.                         flags &= ~PFXOK;
  489.                         goto ok;
  490.                     }
  491.                     break;
  492.                 }
  493.  
  494.                 /*
  495.                  * If we got here, c is not a legal character
  496.                  * for a number.  Stop accumulating digits.
  497.                  */
  498.                 break;
  499.         ok:
  500.                 /*
  501.                  * c is legal: store it and look at the next.
  502.                  */
  503.                 *p++ = c;
  504.                 _gptr++;
  505.                 if (sgetc() == EOF) {
  506.                     seen_eof++;
  507.                     break;        /* EOF */
  508.                 }
  509.                 }
  510.             /*
  511.              * If we had only a sign, it is no good; push
  512.              * back the sign.  If the number ends in `x',
  513.              * it was [sign] '0' 'x', so push back the x
  514.              * and treat it as [sign] '0'.
  515.              */
  516.             if (flags & NDIGITS) {
  517.                 if (p > buf)
  518.                     (void) sputbackc(*(u_char *)--p);
  519.                 goto match_failure;
  520.             }
  521.             c = ((u_char *)p)[-1];
  522.             if (c == 'x' || c == 'X') {
  523.                 --p;
  524.                 (void) sputbackc(c);
  525.             }
  526.             if ((flags & SUPPRESS) == 0) {
  527.                 u_long res;
  528.  
  529.                 *p = 0;
  530.                 res = (*ccfn)(buf, (char **)NULL, base);
  531.                 if (flags & POINTER)
  532.                     *va_arg(ap, void **) = (void *)res;
  533.                 else if (flags & SHORT)
  534.                     *va_arg(ap, short *) = res;
  535.                 else if (flags & LONG)
  536.                     *va_arg(ap, long *) = res;
  537.                 else
  538.                     *va_arg(ap, int *) = res;
  539.                 nassigned++;
  540.             }
  541.             nread += p - buf;
  542.             break;
  543.  
  544. #ifdef FLOATING_POINT
  545.         case CT_FLOAT:
  546.             /* scan a floating point number as if by strtod */
  547.             if (width == 0 || width > sizeof(buf) - 1)
  548.                 width = sizeof(buf) - 1;
  549.             flags |= SIGNOK | NDIGITS | DPTOK | EXPOK;
  550.             for (p = buf; width; width--) {
  551.                 c = *_gptr;
  552.                 /*
  553.                  * This code mimicks the integer conversion
  554.                  * code, but is much simpler.
  555.                  */
  556.                 switch (c) {
  557.  
  558.                 case '0': case '1': case '2': case '3':
  559.                 case '4': case '5': case '6': case '7':
  560.                 case '8': case '9':
  561.                     flags &= ~(SIGNOK | NDIGITS);
  562.                     goto fok;
  563.  
  564.                 case '+': case '-':
  565.                     if (flags & SIGNOK) {
  566.                         flags &= ~SIGNOK;
  567.                         goto fok;
  568.                     }
  569.                     break;
  570.                 case '.':
  571.                     if (flags & DPTOK) {
  572.                         flags &= ~(SIGNOK | DPTOK);
  573.                         goto fok;
  574.                     }
  575.                     break;
  576.                 case 'e': case 'E':
  577.                     /* no exponent without some digits */
  578.                     if ((flags&(NDIGITS|EXPOK)) == EXPOK) {
  579.                         flags =
  580.                             (flags & ~(EXPOK|DPTOK)) |
  581.                             SIGNOK | NDIGITS;
  582.                         goto fok;
  583.                     }
  584.                     break;
  585.                 }
  586.                 break;
  587.         fok:
  588.                 *p++ = c;
  589.                 _gptr++;
  590.                 if (sgetc() == EOF) {
  591.                     seen_eof++;
  592.                     break;    /* EOF */
  593.                 }
  594.             }
  595.             /*
  596.              * If no digits, might be missing exponent digits
  597.              * (just give back the exponent) or might be missing
  598.              * regular digits, but had sign and/or decimal point.
  599.              */
  600.             if (flags & NDIGITS) {
  601.                 if (flags & EXPOK) {
  602.                     /* no digits at all */
  603.                     while (p > buf)
  604.                         sputbackc(*(u_char *)--p);
  605.                     goto match_failure;
  606.                 }
  607.                 /* just a bad exponent (e and maybe sign) */
  608.                 c = *(u_char *)--p;
  609.                 if (c != 'e' && c != 'E') {
  610.                     (void)sputbackc(c);/* sign */
  611.                     c = *(u_char *)--p;
  612.                 }
  613.                 (void) sputbackc(c);
  614.             }
  615.             if ((flags & SUPPRESS) == 0) {
  616.                 double res;
  617.                 *p = 0;
  618. #ifdef USE_DTOA
  619.                 res = strtod(buf, NULL);
  620. #else
  621.                 res = atof(buf);
  622. #endif
  623.                 if (flags & LONG)
  624.                     *va_arg(ap, double *) = res;
  625.                 else
  626.                     *va_arg(ap, float *) = res;
  627.                 nassigned++;
  628.             }
  629.             nread += p - buf;
  630.             break;
  631. #endif /* FLOATING_POINT */
  632.         }
  633.     }
  634. eof_failure:
  635.     seen_eof++;
  636. input_failure:
  637.     if (nassigned == 0)
  638.         nassigned = -1;
  639. match_failure:
  640.     if (stream)
  641.         stream->set(ios::failbit);
  642. done:
  643.     if (stream && seen_eof)
  644.         stream->set(ios::eofbit);
  645.     return (nassigned);
  646. }
  647.  
  648. /*
  649.  * Fill in the given table from the scanset at the given format
  650.  * (just after `[').  Return a pointer to the character past the
  651.  * closing `]'.  The table has a 1 wherever characters should be
  652.  * considered part of the scanset.
  653.  */
  654. static const u_char *__sccl(register char *tab, register const u_char *fmt)
  655. {
  656.     register int c, n, v;
  657.  
  658.     /* first `clear' the whole table */
  659.     c = *fmt++;        /* first char hat => negated scanset */
  660.     if (c == '^') {
  661.         v = 1;        /* default => accept */
  662.         c = *fmt++;    /* get new first char */
  663.     } else
  664.         v = 0;        /* default => reject */
  665.     /* should probably use memset here */
  666.     for (n = 0; n < 256; n++)
  667.         tab[n] = v;
  668.     if (c == 0)
  669.         return (fmt - 1);/* format ended before closing ] */
  670.  
  671.     /*
  672.      * Now set the entries corresponding to the actual scanset
  673.      * to the opposite of the above.
  674.      *
  675.      * The first character may be ']' (or '-') without being special;
  676.      * the last character may be '-'.
  677.      */
  678.     v = 1 - v;
  679.     for (;;) {
  680.         tab[c] = v;        /* take character c */
  681. doswitch:
  682.         n = *fmt++;        /* and examine the next */
  683.         switch (n) {
  684.  
  685.         case 0:            /* format ended too soon */
  686.             return (fmt - 1);
  687.  
  688.         case '-':
  689.             /*
  690.              * A scanset of the form
  691.              *    [01+-]
  692.              * is defined as `the digit 0, the digit 1,
  693.              * the character +, the character -', but
  694.              * the effect of a scanset such as
  695.              *    [a-zA-Z0-9]
  696.              * is implementation defined.  The V7 Unix
  697.              * scanf treats `a-z' as `the letters a through
  698.              * z', but treats `a-a' as `the letter a, the
  699.              * character -, and the letter a'.
  700.              *
  701.              * For compatibility, the `-' is not considerd
  702.              * to define a range if the character following
  703.              * it is either a close bracket (required by ANSI)
  704.              * or is not numerically greater than the character
  705.              * we just stored in the table (c).
  706.              */
  707.             n = *fmt;
  708.             if (n == ']' || n < c) {
  709.                 c = '-';
  710.                 break;    /* resume the for(;;) */
  711.             }
  712.             fmt++;
  713.             do {        /* fill in the range */
  714.                 tab[++c] = v;
  715.             } while (c < n);
  716. #if 1    /* XXX another disgusting compatibility hack */
  717.             /*
  718.              * Alas, the V7 Unix scanf also treats formats
  719.              * such as [a-c-e] as `the letters a through e'.
  720.              * This too is permitted by the standard....
  721.              */
  722.             goto doswitch;
  723. #else
  724.             c = *fmt++;
  725.             if (c == 0)
  726.                 return (fmt - 1);
  727.             if (c == ']')
  728.                 return (fmt);
  729. #endif
  730.             break;
  731.  
  732.         case ']':        /* end of scanset */
  733.             return (fmt);
  734.  
  735.         default:        /* just another character */
  736.             c = n;
  737.             break;
  738.         }
  739.     }
  740.     /* NOTREACHED */
  741. }
  742.  
  743. int streambuf::scan(char const *format ...)
  744. {
  745.     va_list ap;
  746.     va_start(ap, format);
  747.     int count = vscan(format, ap);
  748.     va_end(ap);
  749.     return count;
  750. }
  751.